package com.nh.glory.ware.security.authentication.rest;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.nh.glory.data.mapper.RoleMapper;
import com.nh.glory.data.mapper.UserMapper;
import com.nh.glory.data.model.Role;
import com.nh.glory.data.model.User;
import com.nh.glory.ware.security.model.LoginUserDetails;
import com.nh.glory.ware.security.model.LoginUserDetailsBuilder;
import lombok.AllArgsConstructor;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.List;

@Component
public class AjaxAuthenticationProvider implements AuthenticationProvider {

    private final UserMapper userMapper;
    private final RoleMapper roleMapper;
    private final BCryptPasswordEncoder encoder;

    public AjaxAuthenticationProvider(UserMapper userMapper, RoleMapper roleMapper, BCryptPasswordEncoder encoder) {
        this.userMapper = userMapper;
        this.roleMapper = roleMapper;
        this.encoder = encoder;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        Assert.notNull(authentication, "No authentication data provided");

        String username = (String) authentication.getPrincipal();
        String password = (String) authentication.getCredentials();

        User user = userMapper.selectOne(new QueryWrapper<User>().lambda().eq(User::getAccount, username));
        if(user == null) {
          throw new UsernameNotFoundException("User not found for " + username);
        }

        if (!encoder.matches(password, user.getPassword())) {
            throw new BadCredentialsException("Authentication Failed, username or password not valid");
        }

        Role role = roleMapper.selectById(user.getRoleId());
        if (role == null) {
            throw new InsufficientAuthenticationException("User has no roles assigned");
        }

        List<String> roles = new ArrayList<>(1);
        roles.add(role.getRoleName());
        LoginUserDetails loginUser = LoginUserDetailsBuilder.creatOf(user, roles);
        return new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }

}
